/* Hello, Emacs, this is -*-C-*- */

/* GNUPLOT - estimate.trm */

/*
 * This file is included by ../src/term.c via term.h.
 *
 * This terminal driver supports:
 *   On return from ENHest_put_text()
 *	(*term)->xmax = estimated string width in characters
 *	(*term)->ymax = estimated string height (in tenths of a character height)
 *	ENHest_plaintext = non-enhanced text approximation of original string
 *
 * AUTHORS
 *
 *   Ethan A Merritt - Dec 2004
 *
 */
#include "driver.h"

#ifdef TERM_PROTO
TERM_PUBLIC void ENHest_put_text(unsigned int x, unsigned int y, const char str[]);
TERM_PUBLIC void ENHest_OPEN(char * fontname, double fontsize, double base,
				TBOOLEAN widthflag, TBOOLEAN showflag, int overprint);
TERM_PUBLIC void ENHest_FLUSH(void);
#endif /* TERM_PROTO */

#ifdef TERM_BODY

static double ENHest_x, ENHest_y;
static double ENHest_xsave, ENHest_ysave;
static double ENHest_fragment_width;
static double ENHest_fontsize;
static double ENHest_min_height, ENHest_max_height;
static double ENHest_total_width;
static char *ENHest_plaintext = NULL;
static int ENHest_plaintext_buflen = 0;
static int ENHest_plaintext_pos = 0;

static TBOOLEAN ENHest_opened_string;
static TBOOLEAN ENHest_show = TRUE;
static int ENHest_overprint = 0;
static TBOOLEAN ENHest_widthflag = TRUE;
#define ENHest_font ""
static double ENHest_base;

/* Internal routines for UTF-8 support */
static size_t strwidth_utf8(const char *s);

/* DEBUG */
/* place holder for an estimate of the current font size at the time
 * we switched from a "real" terminal to this special-purpose terminal.
 */
#define ENHest_ORIG_FONTSIZE 12.

TERM_PUBLIC void
ENHest_OPEN(
    char *fontname,
    double fontsize, double base,
    TBOOLEAN widthflag, TBOOLEAN showflag,
    int overprint)
{
    /* There are two special cases:
     * overprint = 3 means save current position
     * overprint = 4 means restore saved position
     */
    if (overprint == 3) {
	ENHest_xsave = ENHest_x;
	ENHest_ysave = ENHest_y;
	return;
    } else if (overprint == 4) {
	ENHest_x = ENHest_xsave;
	ENHest_y = ENHest_ysave;
	return;
    }

    if (!ENHest_opened_string) {
	ENHest_opened_string = TRUE;
	/* Start new text fragment */
	    ENHest_fragment_width = 0;
	/* font size will be used to estimate width of each character */
	    ENHest_fontsize = fontsize;
	/* Scale fractional font height */
	    ENHest_base = base * 1.0;
	    if (ENHest_max_height < ENHest_base + fontsize)
		ENHest_max_height = ENHest_base + fontsize;
	    if (ENHest_min_height > ENHest_base)
		ENHest_min_height = ENHest_base;
	    FPRINTF((stderr,"ENHest_OPEN: base %g fontsize %g  min %g max %g\n",
	    	    base,fontsize,ENHest_min_height,ENHest_max_height));
	/* Keep track of whether we are supposed to show this string */
	    ENHest_show = showflag;
	/* 0/1/2  no overprint / 1st pass / 2nd pass */
	    ENHest_overprint = overprint;
	/* widthflag FALSE means do not update text position after printing */
	    ENHest_widthflag = widthflag;
    }
}

TERM_PUBLIC void
ENHest_FLUSH()
{
    double len = ENHest_fragment_width;

    if (ENHest_opened_string) {
	ENHest_fragment_width = 0;

	if (!ENHest_widthflag)
	    /* don't update position */
	    ;
	else if (ENHest_overprint == 1)
	    /* First pass of overprint, leave position in center of fragment */
	    ENHest_x += len / 2;
	else
	    /* Normal case is to update position to end of fragment */
	    ENHest_x += len;

	ENHest_total_width = GPMAX(ENHest_total_width, ENHest_x);
	ENHest_opened_string = FALSE;
    }
}

TERM_PUBLIC void
ENHest_put_text(unsigned int x, unsigned int y, const char *str)
{
    /* Set up global variables needed by enhanced_recursion() */
    ENHest_fontsize  = ENHest_ORIG_FONTSIZE;
    ENHest_opened_string = FALSE;
    ENHest_max_height = ENHest_fontsize;
    ENHest_min_height = 0.0;
    ENHest_total_width = 0.0;
    strncpy(enhanced_escape_format,".",sizeof(enhanced_escape_format));

    /* buffer in which we will return plaintext version of enhanced text string */
    while (ENHest_plaintext_buflen <= strlen(str)) {
	ENHest_plaintext_buflen += MAX_ID_LEN;
	ENHest_plaintext = gp_realloc(ENHest_plaintext, ENHest_plaintext_buflen+1, "ENHest_plaintext");
    }
    ENHest_plaintext[0] = '\0';
    ENHest_plaintext_pos = 0;

    /* If no enhanced text processing is needed, strlen() is sufficient */
    if (ignore_enhanced_text || (!strpbrk(str, "{}^_@&~\n") && !contains_unicode(str))) {
	if (encoding == S_ENC_UTF8)
	    term->xmax = strwidth_utf8(str);
	else
	    term->xmax = strlen(str);
	term->ymax = 10;	/* 1 character height */
	strcpy(ENHest_plaintext, str);
	return;
    }

    ENHest_x = x;
    ENHest_y = y;

    while (*(str = enhanced_recursion((char *)str, TRUE,
    			ENHest_font, ENHest_fontsize,
			0.0, TRUE, TRUE, 0))) {
	(term->enhanced_flush)();

	enh_err_check(str);
	if (!*++str)
	    break; /* end of string */
    }

    ENHest_plaintext[ENHest_plaintext_pos] = '\0';
    if (ENHest_x > 0.0 && ENHest_x < 1.0)
	ENHest_x = 1;
    term->xmax = ENHest_total_width;
    term->ymax = 10. * (ENHest_max_height - ENHest_min_height)/ENHest_ORIG_FONTSIZE + 0.5;
}

TERM_PUBLIC void
ENHest_writec(int c)
{
    if (c == '\n') {
	ENHest_FLUSH();
	ENHest_opened_string = TRUE;
	ENHest_min_height -= 1.0 * ENHest_fontsize;
	ENHest_base -= 1.0 * ENHest_fontsize;
	ENHest_x = 0;
    }

    if (encoding == S_ENC_UTF8) {
	/* Skip all but the first byte of UTF-8 multi-byte characters. */
	if ((c & 0xc0) != 0x80) {
	    ENHest_fragment_width += 1;
	    /* [most] characters above 0x3000 are square CJK glyphs, */
	    /* which are wider than western characters.              */
	    if ((unsigned char)c >= 0xec)
		ENHest_fragment_width += 1;
	}
    } else
	ENHest_fragment_width += 1;

    ENHest_plaintext[ENHest_plaintext_pos++] = c;
}

/*
 * This routine accounts for multi-byte characters in UTF-8.
 * NB:  It does not return the _number_ of characters in the string, but
 * rather their approximate _width_ in units of typical character width.
 * As with the ENHest_writec() routine, it approximates the width of characters
 * above unicode 0x3000 as being twice that of western alphabetic characters.
 */
size_t strwidth_utf8(const char *s) {
    int i = 0, j = 0;
    while (s[i]) {
       if ((s[i] & 0xc0) != 0x80) {
           j++;
	   if ((unsigned char)(s[i]) >= 0xe3)
		j++;
       }
       i++;
    }
    return j;
}


static struct termentry ENHest = {
    "estimate", NULL,
    1, 1, 1, 1, 1, 1,
    NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL,
    NULL, ENHest_put_text, NULL,
    NULL, NULL, NULL, NULL,
    0, 0,			/* pointsize, flags */
    NULL, NULL, NULL, NULL
#ifdef USE_MOUSE
    , NULL, NULL, NULL, NULL, NULL
#endif
    , NULL, NULL, NULL, NULL
    , NULL
    , ENHest_OPEN, ENHest_FLUSH, ENHest_writec
};

#endif /* TERM_BODY */
